package com.after.saas.file;

import com.after.saas.file.domain.vo.AmountItem;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;


public class OptimizedAmountOffsetProcessor {
    
    /**
     * 优化版本：针对正数金额 > 负数金额且正数行数远大于负数行数的场景
     */
    public static List<AmountItem> processAmountOffsetOptimized(List<AmountItem> items) {
        if (items == null || items.isEmpty()) {
            return new ArrayList<>();
        }
        
        // 深拷贝原始列表
        List<AmountItem> result = items.stream()
                .map(item -> new AmountItem(item.getId(), item.getAmount()))
                .collect(Collectors.toList());
        
        // 分别获取正数和负数项
        List<AmountItem> positiveItems = result.stream()
                .filter(item -> item.getAmount().compareTo(BigDecimal.ZERO) > 0)
                .collect(Collectors.toList());
        
        List<AmountItem> negativeItems = result.stream()
                .filter(item -> item.getAmount().compareTo(BigDecimal.ZERO) < 0)
                .collect(Collectors.toList());
        
        // 计算负数总金额（绝对值）
        BigDecimal totalNegativeAmount = negativeItems.stream()
                .map(AmountItem::getAmount)
                .reduce(BigDecimal.ZERO, BigDecimal::add)
                .abs();
        
        // 由于正数金额总是大于负数金额，直接进行抵消处理
        if (totalNegativeAmount.compareTo(BigDecimal.ZERO) == 0) {
            return result;
        }
        
        // 优化策略：先尝试用单个大额正数项抵消
        Optional<AmountItem> largeEnoughItem = positiveItems.stream()
                .filter(item -> item.getAmount().compareTo(totalNegativeAmount) >= 0)
                .max(Comparator.comparing(AmountItem::getAmount));
        
        if (largeEnoughItem.isPresent()) {
            AmountItem positiveItem = largeEnoughItem.get();
            positiveItem.setDiscountAmount(totalNegativeAmount);
            positiveItem.setAvailableAmount(positiveItem.getAmount().subtract(totalNegativeAmount));
            return result;
        }
        
        // 如果没有单个足够大的项，使用多个正数项组合抵消（按金额降序）
        List<AmountItem> sortedPositives = positiveItems.stream()
                .sorted((a, b) -> b.getAmount().compareTo(a.getAmount()))
                .collect(Collectors.toList());
        
        BigDecimal remainingNegative = totalNegativeAmount;
        
        for (AmountItem positiveItem : sortedPositives) {
            if (remainingNegative.compareTo(BigDecimal.ZERO) <= 0) {
                break;
            }
            
            BigDecimal positiveAmount = positiveItem.getAmount();
            
            if (positiveAmount.compareTo(remainingNegative) <= 0) {
                positiveItem.setDiscountAmount(positiveAmount);
                positiveItem.setAvailableAmount(BigDecimal.ZERO);
                remainingNegative = remainingNegative.subtract(positiveAmount);
            } else {
                positiveItem.setDiscountAmount(remainingNegative);
                positiveItem.setAvailableAmount(positiveAmount.subtract(remainingNegative));
                remainingNegative = BigDecimal.ZERO;
                break;
            }
        }
        
        return result;
    }
    
    /**
     * 高性能版本：最小化对象创建和操作开销
     */
    public static List<AmountItem> processAmountOffsetHighPerformance(List<AmountItem> items) {
        if (items == null || items.isEmpty()) {
            return new ArrayList<>();
        }
        
        List<AmountItem> result = new ArrayList<>(items);
        BigDecimal totalNegativeAmount = BigDecimal.ZERO;
        List<AmountItem> positiveItems = new ArrayList<>();
        
        for (AmountItem item : result) {
            if (item.getAmount().compareTo(BigDecimal.ZERO) > 0) {
                positiveItems.add(item);
            } else if (item.getAmount().compareTo(BigDecimal.ZERO) < 0) {
                totalNegativeAmount = totalNegativeAmount.add(item.getAmount());
            }
        }
        
        totalNegativeAmount = totalNegativeAmount.abs();
        
        if (totalNegativeAmount.compareTo(BigDecimal.ZERO) == 0) {
            return result;
        }
        
        // 使用快速处理逻辑
        positiveItems.sort((a, b) -> b.getAmount().compareTo(a.getAmount()));
        BigDecimal remainingNegative = totalNegativeAmount;
        
        for (AmountItem positiveItem : positiveItems) {
            if (remainingNegative.compareTo(BigDecimal.ZERO) <= 0) break;
            
            BigDecimal positiveAmount = positiveItem.getAmount();
            if (positiveAmount.compareTo(remainingNegative) <= 0) {
                positiveItem.setDiscountAmount(positiveAmount);
                positiveItem.setAvailableAmount(BigDecimal.ZERO);
                remainingNegative = remainingNegative.subtract(positiveAmount);
            } else {
                positiveItem.setDiscountAmount(remainingNegative);
                positiveItem.setAvailableAmount(positiveAmount.subtract(remainingNegative));
                remainingNegative = BigDecimal.ZERO;
                break;
            }
        }
        
        return result;
    }
    
    private static BigDecimal getTotalAmount(List<AmountItem> items) {
        return items.stream()
                .map(AmountItem::getAmount)
                .reduce(BigDecimal.ZERO, BigDecimal::add);
    }
    
    /**
     * 测试用例类
     */
    static class TestCase {
        String name;
        List<AmountItem> input;
        String expectedScenario;
        
        TestCase(String name, List<AmountItem> input, String expectedScenario) {
            this.name = name;
            this.input = input;
            this.expectedScenario = expectedScenario;
        }
    }
    
    /**
     * 完整的测试套件
     */
    public static void runTestSuite() {
        System.out.println("=== 金额抵消处理器测试套件 ===\n");
        
        // 定义测试用例
        List<TestCase> testCases = Arrays.asList(
            // 用例1: 正常情况 - 正数远多于负数
            new TestCase("正常情况-正数远多于负数", 
                Arrays.asList(
                    new AmountItem("P1", new BigDecimal("1000.00")),
                    new AmountItem("P2", new BigDecimal("500.00")),
                    new AmountItem("P3", new BigDecimal("300.00")),
                    new AmountItem("P4", new BigDecimal("200.00")),
                    new AmountItem("P5", new BigDecimal("100.00")),
                    new AmountItem("N1", new BigDecimal("-800.00")),
                    new AmountItem("N2", new BigDecimal("-400.00"))
                ), "正数总额2100 > 负数总额1200，应完全抵消"),
                
            // 用例2: 单个大额正数直接抵消
            new TestCase("单个大额正数直接抵消", 
                Arrays.asList(
                    new AmountItem("P1", new BigDecimal("5000.00")),
                    new AmountItem("P2", new BigDecimal("300.00")),
                    new AmountItem("P3", new BigDecimal("200.00")),
                    new AmountItem("N1", new BigDecimal("-2500.00")),
                    new AmountItem("N2", new BigDecimal("-1500.00"))
                ), "P1单个正数足以抵消全部负数"),
                
            // 用例3: 精确相等情况
            new TestCase("正数负数总额相等", 
                Arrays.asList(
                    new AmountItem("P1", new BigDecimal("600.00")),
                    new AmountItem("P2", new BigDecimal("400.00")),
                    new AmountItem("N1", new BigDecimal("-500.00")),
                    new AmountItem("N2", new BigDecimal("-500.00"))
                ), "正数总额1000 = 负数总额1000，完全抵消"),
                
            // 用例4: 多个正数组合抵消
            new TestCase("多个正数组合抵消", 
                Arrays.asList(
                    new AmountItem("P1", new BigDecimal("400.00")),
                    new AmountItem("P2", new BigDecimal("300.00")),
                    new AmountItem("P3", new BigDecimal("200.00")),
                    new AmountItem("P4", new BigDecimal("100.00")),
                    new AmountItem("N1", new BigDecimal("-800.00"))
                ), "需要P1+P2+P3组合抵消"),
                
            // 用例5: 无负数情况
            new TestCase("无负数情况", 
                Arrays.asList(
                    new AmountItem("P1", new BigDecimal("1000.00")),
                    new AmountItem("P2", new BigDecimal("500.00")),
                    new AmountItem("P3", new BigDecimal("300.00"))
                ), "无负数，所有正数可用金额不变"),
                
            // 用例6: 大量数据测试
            new TestCase("大量数据测试", generateTestData(50, 3), "50个正数，3个负数"),
                
            // 用例7: 边界值测试-极小金额
            new TestCase("极小金额测试", 
                Arrays.asList(
                    new AmountItem("P1", new BigDecimal("0.01")),
                    new AmountItem("P2", new BigDecimal("0.02")),
                    new AmountItem("N1", new BigDecimal("-0.02"))
                ), "极小金额正确处理"),
                
            // 用例8: 边界值测试-极大金额
            new TestCase("极大金额测试", 
                Arrays.asList(
                    new AmountItem("P1", new BigDecimal("999999.99")),
                    new AmountItem("P2", new BigDecimal("500000.00")),
                    new AmountItem("N1", new BigDecimal("-1000000.00"))
                ), "极大金额正确处理")
        );
        
        int passed = 0;
        int failed = 0;
        
        // 执行每个测试用例
        for (TestCase testCase : testCases) {
            System.out.println("┌─────────────────────────────────────────────────────────┐");
            System.out.println("│ 测试用例: " + String.format("%-40s", testCase.name) + "│");
            System.out.println("│ 场景描述: " + String.format("%-38s", testCase.expectedScenario) + "│");
            System.out.println("└─────────────────────────────────────────────────────────┘");
            
            boolean testResult = runTestCase(testCase);
            
            if (testResult) {
                passed++;
                System.out.println("✅ 测试结果: 通过\n");
            } else {
                failed++;
                System.out.println("❌ 测试结果: 失败\n");
            }
            
            try {
                Thread.sleep(100); // 稍微延迟，使输出更清晰
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
        
        // 输出测试总结
        System.out.println("═════════════════════════════════════════════════════════════");
        System.out.println("测试总结:");
        System.out.println("总测试用例: " + testCases.size());
        System.out.println("通过: " + passed + " ✅");
        System.out.println("失败: " + failed + " ❌");
        System.out.println("通过率: " + String.format("%.1f%%", (double)passed / testCases.size() * 100));
        System.out.println("═════════════════════════════════════════════════════════════");
        
        // 性能测试
        runPerformanceTests();
    }
    
    /**
     * 执行单个测试用例
     */
    private static boolean runTestCase(TestCase testCase) {
        try {
            System.out.println("输入数据:");
            testCase.input.forEach(item -> System.out.println("  " + item));
            
            // 使用高性能版本处理
            long startTime = System.nanoTime();
//            List<AmountItem> result = processAmountOffsetHighPerformance(testCase.input);
            List<AmountItem> result = processAmountOffsetOptimized(testCase.input);
            long endTime = System.nanoTime();
            
            System.out.println("\n处理结果:");
            result.forEach(item -> System.out.println("  " + item));
            
            // 验证结果
            boolean isValid = validateResult(result);
            long duration = (endTime - startTime) / 1000; // 转换为微秒
            
            System.out.println("\n验证结果:");
            System.out.println("  数据完整性: " + (isValid ? "✅" : "❌"));
            System.out.println("  处理时间: " + duration + " μs");
            
            return isValid;
            
        } catch (Exception e) {
            System.out.println("  执行异常: " + e.getMessage());
            return false;
        }
    }
    
    /**
     * 验证处理结果是否正确
     */
    private static boolean validateResult(List<AmountItem> result) {
        try {
            BigDecimal totalPositive = result.stream()
                    .filter(item -> item.getAmount().compareTo(BigDecimal.ZERO) > 0)
                    .map(AmountItem::getAmount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
                    
            BigDecimal totalNegative = result.stream()
                    .filter(item -> item.getAmount().compareTo(BigDecimal.ZERO) < 0)
                    .map(AmountItem::getAmount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add)
                    .abs();
                    
            BigDecimal totalDiscount = result.stream()
                    .map(AmountItem::getDiscountAmount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
                    
            BigDecimal totalAvailable = result.stream()
                    .map(AmountItem::getAvailableAmount)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            
            // 验证1: 折扣金额 + 可用金额 = 正数总额
            boolean validation1 = totalDiscount.add(totalAvailable).compareTo(totalPositive) == 0;
            
            // 验证2: 折扣金额 <= 负数总额（因为可能正数总额不足）
            boolean validation2 = totalDiscount.compareTo(totalNegative) <= 0;
            
            // 验证3: 所有金额非负
            boolean validation3 = result.stream()
                    .allMatch(item -> item.getDiscountAmount().compareTo(BigDecimal.ZERO) >= 0 &&
                                     item.getAvailableAmount().compareTo(BigDecimal.ZERO) >= 0);
            
            // 验证4: 如果正数总额 >= 负数总额，则折扣金额应该等于负数总额
            boolean validation4 = true;
            if (totalPositive.compareTo(totalNegative) >= 0) {
                validation4 = totalDiscount.compareTo(totalNegative) == 0;
            }
            
            System.out.println("  验证详情:");
            System.out.println("    ✓ 折扣+可用=正数总额: " + validation1);
            System.out.println("    ✓ 折扣金额≤负数总额: " + validation2);
            System.out.println("    ✓ 所有金额非负: " + validation3);
            System.out.println("    ✓ 完全抵消验证: " + validation4);
            System.out.println("  统计信息:");
            System.out.println("    - 正数总额: " + totalPositive);
            System.out.println("    - 负数总额: " + totalNegative);
            System.out.println("    - 折扣总额: " + totalDiscount);
            System.out.println("    - 可用总额: " + totalAvailable);
            
            return validation1 && validation2 && validation3 && validation4;
            
        } catch (Exception e) {
            System.out.println("  验证异常: " + e.getMessage());
            return false;
        }
    }
    
    /**
     * 性能测试
     */
    private static void runPerformanceTests() {
        System.out.println("\n🎯 性能测试");
        System.out.println("═════════════════════════════════════════════════════════════");
        
        int[] dataSizes = {100, 500, 1000, 5000};
        
        for (int size : dataSizes) {
            List<AmountItem> testData = generateTestData(size, size / 20); // 5%的负数
            
            long startTime = System.nanoTime();
            List<AmountItem> result = processAmountOffsetHighPerformance(testData);
            long endTime = System.nanoTime();
            
            long duration = (endTime - startTime) / 1000000; // 转换为毫秒
            boolean isValid = validateResult(result);
            
            System.out.println(String.format("数据量: %-6d | 时间: %-5dms | 验证: %s", 
                size, duration, isValid ? "✅" : "❌"));
        }
    }
    
    /**
     * 生成测试数据
     */
    private static List<AmountItem> generateTestData(int positiveCount, int negativeCount) {
        List<AmountItem> items = new ArrayList<>();
        Random random = new Random(42);
        
        // 生成正数项
        for (int i = 1; i <= positiveCount; i++) {
            BigDecimal amount = new BigDecimal(100 + random.nextInt(400));
            items.add(new AmountItem("P" + i, amount));
        }
        
        // 生成负数项
        for (int i = 1; i <= negativeCount; i++) {
            BigDecimal amount = new BigDecimal(-(500 + random.nextInt(1000)));
            items.add(new AmountItem("N" + i, amount));
        }
        
        Collections.shuffle(items, new Random(42));
        return items;
    }
    
    /**
     * 详细测试报告
     */
    public static void generateDetailedReport() {
        System.out.println("\n📊 详细测试报告");
        System.out.println("═════════════════════════════════════════════════════════════");
        
        // 测试特殊场景
        testSpecialScenarios();
        
        // 测试边界条件
        testBoundaryConditions();
        
        // 测试错误处理
        testErrorHandling();
    }
    
    private static void testSpecialScenarios() {
        System.out.println("\n特殊场景测试:");
        
        // 空列表测试
        List<AmountItem> emptyList = Collections.emptyList();
        List<AmountItem> result1 = processAmountOffsetHighPerformance(emptyList);
        System.out.println("空列表测试: " + (result1.isEmpty() ? "✅" : "❌"));
        
        // 单元素测试
        List<AmountItem> singleItem = Arrays.asList(new AmountItem("P1", new BigDecimal("100.00")));
        List<AmountItem> result2 = processAmountOffsetHighPerformance(singleItem);
        System.out.println("单元素测试: " + (result2.size() == 1 ? "✅" : "❌"));
        
        // 只有负数测试
        List<AmountItem> onlyNegative = Arrays.asList(
            new AmountItem("N1", new BigDecimal("-100.00")),
            new AmountItem("N2", new BigDecimal("-200.00"))
        );
        List<AmountItem> result3 = processAmountOffsetHighPerformance(onlyNegative);
        System.out.println("只有负数测试: " + (result3.size() == 2 ? "✅" : "❌"));
    }
    
    private static void testBoundaryConditions() {
        System.out.println("\n边界条件测试:");
        
        // 零值测试
        List<AmountItem> zeroAmount = Arrays.asList(
            new AmountItem("P1", BigDecimal.ZERO),
            new AmountItem("N1", BigDecimal.ZERO)
        );
        List<AmountItem> result1 = processAmountOffsetHighPerformance(zeroAmount);
        System.out.println("零值金额测试: " + (validateResult(result1) ? "✅" : "❌"));
        
        // 极大值测试
        List<AmountItem> largeAmounts = Arrays.asList(
            new AmountItem("P1", new BigDecimal("999999999.99")),
            new AmountItem("N1", new BigDecimal("-500000000.00"))
        );
        List<AmountItem> result2 = processAmountOffsetHighPerformance(largeAmounts);
        System.out.println("极大金额测试: " + (validateResult(result2) ? "✅" : "❌"));
    }
    
    private static void testErrorHandling() {
        System.out.println("\n错误处理测试:");
        
        // null值测试
        try {
            processAmountOffsetHighPerformance(null);
            System.out.println("null输入测试: ✅");
        } catch (Exception e) {
            System.out.println("null输入测试: ❌ - " + e.getMessage());
        }
    }
    
    /**
     * 主方法
     */
    public static void main(String[] args) {
        // 运行完整测试套件
        runTestSuite();
        
        // 生成详细报告
        generateDetailedReport();
        
        System.out.println("\n🎉 所有测试执行完成！");
    }
}